using System;
using System.Collections.Generic;
using System.Collections;
using System.Text;
using System.IO;

namespace MP3Archiver
{
    public class ProcessedEventArgs : EventArgs
    {
        private string mFileName;
        private bool mProblem;
        
        public string GetFileName()
        {
            return mFileName;
        }
        public bool isProblem()
        {
            return mProblem;
        }
        public ProcessedEventArgs(string fileName, bool problem) { mFileName = fileName; mProblem = problem; }
    }

    class Archiver
    {


        public delegate void ProcessedFileEventHandler(object sender, ProcessedEventArgs e);
        public delegate void CompleteEventHandler(object sender, EventArgs e);

        public event ProcessedFileEventHandler processedFile;

        public event CompleteEventHandler completed;


        private ArrayList mFolders;
        private string mDestinationFolder;
        private bool mRecurse = true;
        private bool mRemoveSourceFile = false;
        private ArrayList mMusicTypesToProcess;

        private string PROBLEM_LOG;

        public Archiver(string destinationFolder, bool recurse)
        {
            mDestinationFolder = destinationFolder;
            mRecurse = recurse;
            mFolders = new ArrayList();
            mMusicTypesToProcess = new ArrayList();

        }

        public Archiver()
        {
            mFolders = new ArrayList();
            mMusicTypesToProcess = new ArrayList();
        }

        public void AddMusicTypeToProcess(MusicType type)
        {
            mMusicTypesToProcess.Add(type);
        }

        public void AddFolder(string path)
        {
            mFolders.Add(path);
        }

        public void SetDestinationFolder(string destinationFolder)
        {
            mDestinationFolder = destinationFolder;
        }
        public void SetRecurse(bool recurse)
        {
            mRecurse = recurse;
        }
        public void SetRemoveSourceFile(bool removeSourceFile)
        {
            mRemoveSourceFile = removeSourceFile;
        }
        

        public void Process()
        {
            if (mDestinationFolder == string.Empty) { throw new Exception("Destination folder not set"); }
            PROBLEM_LOG = mDestinationFolder + "\\problemlog.txt";
            foreach (string rootDirectory in mFolders)
            {
                ProcessDirectory(rootDirectory);

            }

            completed(this, null);

        }

        private void ProcessDirectory(string dir)
        {
            foreach (string file in Directory.GetFiles(dir))
            {
                ProcessFile(file);
            }

            if (mRecurse == true)
            {
                foreach (string childDirectory in Directory.GetDirectories(dir))
                {
                    //recurse
                    ProcessDirectory(childDirectory);
                }
            }



        }

        private void ProcessFile(string file)
        {
            MusicType type = MusicFileType(file);

            if (type != MusicType.NONMUSICFILE && mMusicTypesToProcess.Contains(type) == true)
            {
                try
                {
                    string folder;
                    //get tag
                    switch (type)
                    {
                        case MusicType.MP3:
                            ID3v1 id3 = new ID3v1(file);
                            id3.Read();
                            folder = mDestinationFolder + "\\" + CleanDirectoryName(id3.Artist) + "\\" + CleanDirectoryName(id3.Album);
                            break;
                        case MusicType.WMA:
                            WMAID3.WMAID3Tag wmaid3 = new WMAID3.WMAID3Tag(file);
                            folder = mDestinationFolder + "\\" + CleanDirectoryName(wmaid3.artist) + "\\" + CleanDirectoryName(wmaid3.album);
                            break;
                        default:
                            throw new Exception("Cannot handle music type: " + type.ToString());
                    }
                   

                    //create folders from ID3 if not already there
                    TryCreatingFolder(folder);

                    //now copy the file
                    File.Copy(file, folder + "\\" + GetFileName(file), true);

                    //raise event
                    processedFile(this, new ProcessedEventArgs(file,false));
                }
                catch (Exception ex)
                {
                    //could not handle this file properly so log it and put file in problem dir
                    LogProblemFile(ex, file);
                    HandleProblemFile(file);
                    //raise event
                    processedFile(this, new ProcessedEventArgs(file,true));

                }

            }



        }

        private void TryCreatingFolder(string dir)
        {
            if (!Directory.Exists(dir)) { Directory.CreateDirectory(dir); }
        }



        private string GetFileName(string filePath)
        {
            return filePath.Substring(filePath.LastIndexOf("\\") + 1);
        }

        private void HandleProblemFile(string file)
        {
            string problemFolder = mDestinationFolder + "\\problemfiles";
            TryCreatingFolder(problemFolder);
            File.Copy(file, problemFolder + "\\" + GetFileName(file), true);

        }

        private void LogProblemFile(Exception ex, string file)
        {

            string contents = string.Empty;
            contents = file + " Exception: " + ex.Message;
            File.AppendAllText(PROBLEM_LOG, contents);
        }

        private string CleanDirectoryName(string dir)
        {
            //   \/:*?<>|
            dir = dir.Replace(@"\", " ");
            dir = dir.Replace(@"/", " ");
            dir = dir.Replace(@":", " ");
            dir = dir.Replace(@"*", " ");
            dir = dir.Replace(@"?", " ");
            dir = dir.Replace(@">", " ");
            dir = dir.Replace(@"<", " ");
            dir = dir.Replace(@"|", " ");

            return dir;
        }

        public static MusicType MusicFileType(string file)
        {
            string extension = file.Substring(file.LastIndexOf(".") + 1);
            if (extension == "mp3" || extension == "MP3") { return MusicType.MP3; }
            if (extension == "wma" || extension == "WMA") { return MusicType.WMA; }
            return MusicType.NONMUSICFILE;
        }



        public enum MusicType
        {
            MP3,
            WMA,
            NONMUSICFILE
        }













    }
}
